home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / LaserWriterIIsc (New GX v1.1) / UniversalMessageIntf.c < prev    next >
Encoding:
Text File  |  1996-06-15  |  61.4 KB  |  1,898 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     UniversalMessageIntf.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which override the universal imaging 
  7.     messages that the LaserWriter SC utilizes.
  8.         
  9. COPYRIGHT
  10.     Copyright Apple Computer, Inc. 1989-1996
  11.     All rights reserved. 
  12.     
  13. MODIFICATION HISTORY
  14.      6/14/96 - cn  - Updated to support Universal Interfaces 2.1.
  15.  
  16. INTERFACE ROUTINES:
  17.     SD_Initialize
  18.     SD_ShutDown
  19.     SD_DefaultPrinter
  20.     SD_DespoolPage
  21.     SD_SetupImageData
  22.     SD_OpenConnection
  23.     SD_CloseConnection
  24.     SD_StartSendPage
  25.     SD_FinishSendPage
  26.     SD_WriteData
  27.     SD_CheckStatus
  28.     SD_GetDeviceStatus
  29.     SD_CreateImageFile
  30.     SD_RasterDataIn
  31.     SD_ChooserMessage
  32.  
  33. -------------------------------------------------------------------------------- */
  34.  
  35. // Include the standard Mac header files 
  36. #include "MacIncludes.h"
  37.  
  38. // Include the new QuickDraw GX graphics header files 
  39. #include <GXGraphics.h>
  40. #include <GraphicsLibraries.h>
  41. #include <GXMath.h>
  42. #include <QDLibrary.h>
  43.  
  44. // Include the required Printing Manager header files 
  45. #include <GXPrinting.h>
  46. #include <GXPrinterDrivers.h>
  47. #include <Collections.h>
  48. #include <GXMessages.h>
  49.  
  50. #include <GXExceptions.h>
  51.  
  52. // Include the internal driver constants and types used by this module 
  53. #include "LaserSCResources.h"
  54. #include "UniversalMessageIntf.h"
  55. #include "LaserSCIntf.h"
  56. #include "SCPrinterStatus.h"
  57.  
  58. /***************************************************************************************
  59. *                                         INTERNAL ROUTINES                                                     *
  60. ***************************************************************************************/                        
  61.  
  62. /****************************************************************************************
  63.  
  64.                             IsGXVersionNewEnough
  65.                             
  66.     function:
  67.                 This routine checks to see if our driver is too new for the
  68.                 installed version of QuickDraw GX.  We require version 1.1,
  69.                 since we rely on the 1.1 gxSetupPageImageData message.
  70.                 
  71.     parameters:        
  72.                 anErr            error result (noErr or kSilentError.)
  73.                                 kSilentError is a positive number.  QDGX
  74.                                 will not alert for print jobs that fail
  75.                                 with positive error codes.
  76.                 
  77.     returns:
  78.                 true if version is ok, otherwise false.
  79.  
  80. ****************************************************************************************/
  81.  
  82. Boolean IsGXVersionNewEnough(OSErr *anErr)
  83. {
  84.     long                    theVersion;
  85.     gxStatusRecord        *pStatus;
  86.     
  87.     // We require version 1.1 or later, so make sure we have it.
  88.  
  89.     if ((Gestalt(gestaltGXVersion, &theVersion) == noErr) &&
  90.          (theVersion >= 0x00010100))
  91.         *anErr = noErr;
  92.     else
  93.     {
  94.         // Allocate a status record large enough to handle status with the largest buffer size. 
  95.     
  96.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
  97.         *anErr = MemError();
  98.         require(*anErr == noErr, NewPtrClearFailed);
  99.     
  100.         // Initialize the appropriate fields within the status record 
  101.         
  102.         pStatus->statusOwner         = 'drvr';
  103.         pStatus->statResId         = kEngineStatusStatID;
  104.         pStatus->statResIndex     = kDriverTooNewIdx;
  105.         pStatus->bufferLen         = gxDefaultStatusBufferSize;
  106.  
  107.         // Now display the alert to the user
  108.         do
  109.         {
  110.             // Issue the alert to the user
  111.             *anErr = GXAlertTheUser(pStatus);
  112.         }
  113.         while (pStatus->dialogResult == 0);
  114.         
  115.         // Kill the status pointer
  116.         DisposPtr((Ptr) pStatus);
  117.  
  118. NewPtrClearFailed:
  119.  
  120.         // Return a positive error code, so GX will not put up another alert,
  121.         // but will put any job in progress on hold.
  122.  
  123.         *anErr = kSilentError;
  124.     }
  125.  
  126.     return ((*anErr == noErr)? true: false);
  127. }
  128.  
  129.  
  130. /****************************************************************************************
  131.  
  132.                             FixRoundRectangle
  133.                             
  134.     function:
  135.                 This routine is a utility function which rounds the coordinate values within 
  136.                 the rectangle passed in.
  137.                 
  138.     parameters:                
  139.                 r            rectangle whose coordinates are to be rounded
  140.                 
  141.     returns:
  142.                 None
  143.     
  144. ****************************************************************************************/
  145. void FixRoundRectangle(gxRectangle *r)
  146. {
  147.     r->top         = ff(FixRound(r->top));
  148.     r->left         = ff(FixRound(r->left));
  149.     r->bottom     = ff(FixRound(r->bottom));
  150.     r->right     = ff(FixRound(r->right));
  151. }
  152. /* FixRoundRectangle */
  153.  
  154.  
  155. /****************************************************************************************
  156.  
  157.                             AlignPage
  158.                             
  159.     function:
  160.                 This routine is called to adjust the raster imaging system's page size
  161.                 rectangle so that it's zero based and long word aligned.
  162.                 It also returns a QuickDraw device rectangle which represents the page
  163.                 centered (left to right) in the SC's imaging area.  The device rectangle is 
  164.                 used to set the margins on the printer in SD_StartSendPage.
  165.                 
  166.     parameters:    
  167.                 pageBounds        raster imaging system's pageSize rect
  168.                 deviceRect        rectangle representing the device rectangle for the LWSC
  169.                 maxPageHeight    maximum height allowed for the pageBounds and deviceRect rectangles
  170.                 
  171.     returns:
  172.                 None
  173.     
  174. ****************************************************************************************/
  175. void AlignPage(gxRectangle *pageBounds, Rect *deviceRect, Fixed maxPageHeight)
  176. {
  177.     gxRectangle        tempBounds;
  178.     Fixed                leftMargin;
  179.     Fixed                width;
  180.     short                leftEdge;
  181.     Fixed                paperWidth;
  182.     
  183.     // First force the pageBounds rectangle to be zero based.
  184.  
  185.     pageBounds->right -= pageBounds->left;
  186.     pageBounds->left = ff(0);
  187.     pageBounds->bottom -= pageBounds->top;
  188.     pageBounds->top = ff(0);
  189.  
  190.     // Force the page size rectangle's width to be within the max. range 
  191.     if (pageBounds->right > kMaxPageWidth)
  192.         pageBounds->right = kMaxPageWidth;
  193.     
  194.     // Force the page size rectangle's height to be within the max. range
  195.     
  196.     if (pageBounds->bottom > maxPageHeight)
  197.         pageBounds->bottom = maxPageHeight;
  198.  
  199.     // Force the page to be long-aligned because the offscreen code forces long alignment. 
  200.     // We do this by long aligning the page width, and then resetting the left and 
  201.     // right edges. 
  202.     
  203.     width = ( (pageBounds->right + ff(31)) >> (5+16)) << (5+16);
  204.     
  205.     pageBounds->right = width;
  206.     FixRoundRectangle(pageBounds);
  207.     
  208.     // Now we create the deviceRect starting with the adjusted pageSize rectangle 
  209.     tempBounds = *pageBounds;
  210.     
  211.     // Center the page (left to right) on the engine.  The top margin is always the minimum margin 
  212.  
  213.     tempBounds.top += kMinSCTopMargin;
  214.     tempBounds.bottom += kMinSCTopMargin;
  215.  
  216.     paperWidth = pageBounds->right - pageBounds->left;
  217.     leftMargin = (kMaxPaperWidth - paperWidth) >> 1;
  218.     leftEdge = (((leftMargin >> 16) + 7 ) >> 3) << 3;    // ( (margin + 7) / 8) * 8
  219.     tempBounds.left = ff(leftEdge);
  220.     tempBounds.right = tempBounds.left + width;
  221.     
  222.     FixRoundRectangle(&tempBounds);
  223.     FixedRectToShort(&tempBounds, deviceRect);
  224. }
  225. /* AlignPage */
  226.  
  227.  
  228. /****************************************************************************************
  229.  
  230.                             JobIsBestQuality
  231.                             
  232.     function:
  233.                 This routine is called to determine if the job the driver is currently
  234.                 processing is to be output in best quality or rough quality. The function
  235.                 returns true if best quality, and false otherwise.
  236.                 
  237.     parameters:    
  238.                 None
  239.                 
  240.     returns:
  241.                 Boolean        true if best quality job; false otherwise
  242.     
  243. ****************************************************************************************/
  244. Boolean JobIsBestQuality(void)
  245. {
  246.     OSErr                anErr;
  247.     Boolean            isFinal;
  248.     gxQualityInfo    jobQualitySettings;
  249.     long                itemSize = sizeof(jobQualitySettings);
  250.  
  251.     // Retrieve the quality setting info from the job
  252.     anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
  253.     check(anErr == noErr);
  254.     
  255.     isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
  256.  
  257.     return(isFinal);
  258. }
  259. /* JobIsBestQuality */
  260.  
  261.  
  262. /****************************************************************************************
  263.  
  264.                             SC_HandleManualFeed
  265.                             
  266.     function:
  267.                 This routine is called at FinishSendPage time when the user needs to be
  268.                 prompted to place the correct paper into the printer for a manual feed
  269.                 job.  This routine calls ResolvePrinterProblem to prompt the user
  270.                 and field his responses.  If the user decides to abort the print job, then
  271.                 this routine will return an error of prUserAbortErr.  If the problem
  272.                 is resolved successfully, then this routine returns noErr.
  273.                 
  274.     parameters:    
  275.                 thePaperType        the Paper Type that should be loaded into the printer
  276.                 
  277.     returns:
  278.                 OSErr
  279.     
  280. ****************************************************************************************/
  281. OSErr SC_HandleManualFeed(gxPaperType thePaperType)
  282. {
  283.     OSErr        anErr;
  284.     short        dialogResult;
  285.     long        printerProblem;
  286.  
  287.     // Set printerProblem to indicate the type of problem encountered 
  288.     
  289.     SetPrinterProblemStatResIndex(kOutOfPaperStatIdx, &printerProblem);
  290.     SetPrinterProblemStatResID(kTransmissionStatID, &printerProblem);
  291.  
  292.     // Prompt the user to put paper into the printer.  This routine will return anErr of 
  293.     // prUserAbortErr if the user aborts the print job. 
  294.     
  295.     anErr = ResolvePrinterProblem(printerProblem, isManualFeed, thePaperType, &dialogResult);
  296.     require(anErr == noErr, ResolvePrinterProblem);
  297.     
  298.     switch (dialogResult)
  299.     {
  300.         case 0:
  301.         case ok:
  302.             // User loaded the paper and may or may not have clicked OK by the time we discovered 
  303.             // that the printer now has paper. 
  304.             break;
  305.             
  306.         case gxAutoFeedButtonId:
  307.             // User wishes to do the remainder of the job using the paper cassette. Update job to 
  308.             // relfect auto-feed and tell the printer to feed paper from the cassette. 
  309.             
  310.             {
  311.                 Collection jobCollection;
  312.                 gxPaperFeedInfo paperFeed;
  313.                 gxTrayFeedInfo trayFeedInfo;
  314.                 long itemSize = sizeof(trayFeedInfo);
  315.                 
  316.                 jobCollection = GXGetJobCollection( GXGetJob() );
  317.                 
  318.                 /* Update for job */
  319.                 paperFeed.autoFeed = true;
  320.                 (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
  321.                 
  322.                 /* Update as it may be reused */
  323.                 anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  324.                 if (anErr == noErr) {
  325.                     trayFeedInfo.manualFeedThisPage = false;    /* Other trayInfo fields are still valid */
  326.                     (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
  327.                 }
  328.             }
  329.  
  330.             // Tell printer to switch to paper feed from the cassette 
  331.             anErr = LaserSC_SetBuffandFeedMode(    !isManualFeed, //    T => do manual feed; F => auto-feed
  332.                                                             true);            // T => do buffered printing; F => wait for Print command to complete
  333.             require(anErr == noErr, LaserSC_SetBuffandFeedMode);
  334.             
  335.             break;
  336.  
  337.         default:
  338.             check(0);
  339.             break;
  340.     }
  341.  
  342.     
  343. /******* Clean-up *******/
  344.  
  345. LaserSC_SetBuffandFeedMode:
  346. ResolvePrinterProblem:        
  347.     return(anErr);
  348. }
  349. /* SC_HandleManualFeed */
  350.  
  351.  
  352. /********************************************************************************************
  353.  
  354.                                         GenTIBProgram
  355.     function:
  356.                     GenTIBProgram creates a generic Transfer Instruction Block program which is used to
  357.                     perform all SCSI data transfer operations (refer to SCSI Manager documentation for
  358.                     info. on TIB's). It uses the function's parameters to customize the data transfer
  359.                     operations of the TIB program.
  360.     
  361.     parameters:
  362.                     tibProgram                Pointer to the TIB program generated (returned)
  363.                     dataBuffer                Pointer to buffer to be used for input or output data xfer
  364.                     bytesToXfer                Total number of bytes to send or receive
  365.                     bytesPerChunk            Number of bytes to send or receive in each chunk (during TIB transfer)
  366.     
  367.     returns:
  368.                     None
  369.                     
  370. ********************************************************************************************/
  371. void GenTIBProgram(SCSIInstr    tibProgram[], 
  372.                          Ptr            dataBuffer, 
  373.                          long            bytesToXfer, 
  374.                          long            bytesPerChunk)
  375. {    
  376.     long        numChunks;
  377.     long        numRemBytes;
  378.     
  379.     numChunks = bytesToXfer / bytesPerChunk;        // Integral number of byte chunks to send
  380.     numRemBytes = bytesToXfer % bytesPerChunk;    //    Leftover characters to be sent/received
  381.  
  382.                                                                                             //        Program starts here
  383.     tibProgram[0].scOpcode = scLoop;                                                //        count -= 1
  384.     tibProgram[0].scParam1 = 60;                                                    //        if count > 0 then goto A
  385.     tibProgram[0].scParam2 = numChunks + 1;
  386.     
  387.     tibProgram[1].scOpcode = scLoop;                                                // C:    count -= 1
  388.     tibProgram[1].scParam1 = 20;                                                    //        if count > 0 then goto B
  389.     tibProgram[1].scParam2 = numRemBytes + 1;
  390.     
  391.     tibProgram[2].scOpcode = scStop;                                                //        Terminate program
  392.     tibProgram[2].scParam1 = 0;
  393.     tibProgram[2].scParam2 = 0;
  394.     
  395.     tibProgram[3].scOpcode = scMove;                                                //    B:    Place current dataBuffer pointer into next
  396.     tibProgram[3].scParam1 = (unsigned long) &tibProgram[6].scParam1;    //        instruction
  397.     tibProgram[3].scParam2 = (unsigned long) &tibProgram[4].scParam1;
  398.     
  399.     tibProgram[4].scOpcode = scNoInc;                                            //        Perform data xfer to/from dataBuffer for numRemBytes
  400.     tibProgram[4].scParam1 = (unsigned long) dataBuffer;                    //        Address is set by previous scMove instruction
  401.     tibProgram[4].scParam2 = numRemBytes;
  402.     
  403.     tibProgram[5].scOpcode = scStop;                                                //        Terminate the program
  404.     tibProgram[5].scParam1 = 0;
  405.     tibProgram[5].scParam2 = 0;
  406.             
  407.     tibProgram[6].scOpcode = scInc;                                                //    A:    Perform data xfer to/from dataBuffer for bytesPerChunk
  408.     tibProgram[6].scParam1 = (unsigned long) dataBuffer;                    //        dataBuffer += bytesPerChunk
  409.     tibProgram[6].scParam2 = bytesPerChunk;
  410.     
  411.     tibProgram[7].scOpcode = scLoop;                                                //        count -= 1; 
  412.     tibProgram[7].scParam1 = -10;                                                    //        if count > 0 then goto A
  413.     tibProgram[7].scParam2 = numChunks;
  414.     
  415.     tibProgram[8].scOpcode = scLoop;                                                //        goto C
  416.     tibProgram[8].scParam1 = -70;                                                    //        
  417.     tibProgram[8].scParam2 = 2;
  418. }
  419. /* GenTIBProgram */
  420.  
  421.  
  422. /********************************************************************************************
  423.  
  424.                                         WaitForPageToPrint
  425.     function:
  426.                     WaitForPageToPrint is called to force the current printer's page buffer to be
  427.                     printed.  It handles all error conditions and alerts the user as necessary.  This
  428.                     routine will return when the page has been printed, the user aborted the job, or
  429.                     some fatal printer error was encountered.  This routine assumes we've already started
  430.                     the page printing by an earlier call to LaserSC_PrintPage (performed in the
  431.                     SD_FinishSendPage routine).
  432.     
  433.     parameters:
  434.                     manualFeed            true => paper is being manually fed; false => paper is auto-fed
  435.                     thePaperType        paper type of the paper that should be in the printer
  436.     returns:
  437.                     OSErr
  438.                     
  439. ********************************************************************************************/
  440. OSErr WaitForPageToPrint(    Boolean        manualFeed,
  441.                                     gxPaperType    thePaperType) 
  442. {    
  443.     OSErr        anErr = noErr;
  444.     OSErr        idleErr = noErr;
  445.     short        deviceStatus;
  446.     
  447.     // Continue looping until the page is printed, the user aborts, or a fatal error occurs
  448.     
  449.     while (true)
  450.     {
  451.         // Now we must wait until the device is no longer busy (page printed OK) or some problem occurred
  452.         do
  453.         {
  454.             // Get the latest status info from the printer
  455.             
  456.             anErr = LaserSC_GetDeviceStatus(&deviceStatus);
  457.             require(anErr == noErr, LaserSC_GetDeviceStatus);
  458.             
  459.             // Let the client app have a chance to run
  460.             if (idleErr == noErr)
  461.                 idleErr = GXJobIdle();
  462.             else
  463.                 (void) GXJobIdle();
  464.         }
  465.         while (deviceStatus == kBusy);
  466.         
  467.         // no errors? pick up the idling error
  468.         if (anErr == noErr)
  469.             anErr = idleErr;
  470.             
  471.         // If the device is now ready, then the page must have printed without error 
  472.         if (deviceStatus == kGoodCondition)
  473.         {
  474.             break;
  475.         }
  476.         else    // Device is not ready; see what problem it may have 
  477.         {
  478.             long        printerProblem;
  479.         
  480.             // Status the printer to determine the problem it's experiencing 
  481.  
  482.             anErr = FindPrinterProblem(&printerProblem, nil);
  483.             require(anErr == noErr, FindPrinterProblem);
  484.  
  485.             // If the printer is out of paper and we're doing a manual feed job, then alert 
  486.             // the user to put paper into the printer. 
  487.  
  488.             if ( (GetStatResIndex(printerProblem) == kOutOfPaperStatIdx) && manualFeed )
  489.             {
  490.                 // Tell the user to put in the paper 
  491.                 anErr = SC_HandleManualFeed(thePaperType);
  492.                 
  493.                 // If the error returned is prUserAbortErr, then the user has cancelled the print job 
  494.                 if (anErr != gxPrUserAbortErr)
  495.                 {
  496.                     gxTrayFeedInfo        trayFeedInfo;
  497.                     long                    itemSize = sizeof(trayFeedInfo);
  498.                     
  499.                     // If no other error has occurred, then we loop around and try to re-print the page 
  500.                     require(anErr == noErr, SC_HandleManualFeed);
  501.                     
  502.                     // Check for switch to auto-feed
  503.                     anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  504.                     require(anErr == noErr, GetCollectionItem);
  505.                     
  506.                     // Update cached value if it changed
  507.                     if (! trayFeedInfo.manualFeedThisPage) {
  508.                         manualFeed = false;
  509.                         
  510.                         /* Can pass paper type reference as this IS device communication time */
  511.                         anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
  512.                         nrequire(anErr, GXCheckStatus);
  513.                         
  514.                         /* No need to reset tray from gxTrayFeedInfo.feedTrayIndex as there is only one tray! */
  515.                     }
  516.                 }
  517.                 else    // User canceled manual feed dialog => print job has been cancelled 
  518.                     break;
  519.             }
  520.             else    // Printer is experiencing some other problem; prompt user to resolve it 
  521.             {
  522.                 short        dialogResult;
  523.  
  524.                 anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
  525.                 require(anErr == noErr, ResolvePrinterProblem);
  526.             }
  527.  
  528.             // If we get here, the printer problem has been corrected so we need to re-issue the
  529.             // print command. 
  530.     
  531.             anErr = LaserSC_PrintPage(    false,             // T => print at 8 page per minute rate; F => print normal rate
  532.                                                 false);             // T => clear printer's page buffer while printing; F => don't clear buffer
  533.             require(anErr == noErr, LaserSC_PrintPage);
  534.         }
  535.     } // while 
  536.  
  537.  
  538. /******* Clean-up *******/
  539.  
  540. LaserSC_PrintPage:
  541. ResolvePrinterProblem:
  542. GXCheckStatus:
  543. GetCollectionItem:
  544. SC_HandleManualFeed:
  545. FindPrinterProblem:
  546. JobIdleFails:
  547. LaserSC_GetDeviceStatus:
  548.     return(anErr);
  549. }
  550. /* WaitForPageToPrint */
  551.  
  552.  
  553. /***************************************************************************************
  554. *                                         INTERFACE ROUTINES                                                     *
  555. ***************************************************************************************/                        
  556.  
  557. /****************************************************************************************
  558.  
  559.                             SD_Initialize
  560.                             
  561.     function:
  562.                 This routine is called when a new job is created to perform some job-oriented
  563.                 task, such as conducting dialogs, spooling, and imaging.  It allocates the
  564.                 driver's globals handle and initializes it.
  565.                 
  566.     parameters:    
  567.                 None
  568.                 
  569.     returns:
  570.                 OSErr
  571.     
  572. ****************************************************************************************/
  573. OSErr SD_Initialize(void)
  574. {
  575.     OSErr                 anErr;
  576.     SpecGlobalsHdl     hGlobals;
  577.     
  578.     // Allocate the driver's global handle 
  579.  
  580.     hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
  581.     anErr = MemError();
  582.     require(anErr == noErr, NewHandleClear);
  583.     
  584.     // Tell the Printing Manager to save our globals handle for us 
  585.     SetMessageHandlerInstanceContext(hGlobals);
  586.  
  587.     return(anErr);
  588.     
  589.     
  590. /******* Clean-up *******/
  591.  
  592. NewHandleClear:
  593.     return(anErr);
  594. }
  595. /* SD_Initialize */
  596.  
  597.  
  598. /****************************************************************************************
  599.  
  600.                             SD_ShutDown
  601.                             
  602.     function:
  603.                 This routine is called when a job-oriented task has completed and the 
  604.                 message chain is being destroyed.  This routine disposes of the driver's
  605.                 globals handle..
  606.                 
  607.     parameters:        
  608.                 None
  609.                 
  610.     returns:
  611.                 OSErr
  612.     
  613. ****************************************************************************************/
  614. OSErr SD_ShutDown(void)
  615. {
  616.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  617.     
  618.     // Dump the driver's globals handle if it was allocated 
  619.  
  620.     if (hGlobals != nil)
  621.         DisposHandle((Handle) hGlobals);
  622.     
  623.     // Make sure the Printing Manager no longer has a reference to our globals handle 
  624.     SetMessageHandlerInstanceContext(nil);
  625.         
  626.     return(noErr);
  627. }
  628. /* SD_ShutDown */
  629.  
  630.  
  631. /****************************************************************************************
  632.  
  633.                             SD_DefaultPrinter
  634.                             
  635.     function:
  636.                 This routine is called when a new printer object is being created as a
  637.                 result of someone having called NewJob.  This message gives the driver the
  638.                 opportunity to add any information we want to the new printer object.  In
  639.                 this case, we add a new viewDevice to the printer object which will allow
  640.                 the client application to format a document for this specific device.
  641.                 
  642.     parameters:                
  643.                 thePrinter        the newly allocated printer object
  644.     returns:
  645.                 OSErr
  646.                 
  647. ****************************************************************************************/
  648. OSErr SD_DefaultPrinter(gxPrinter thePrinter)
  649. {
  650.     OSErr             anErr;
  651.     gxViewDevice     vd;
  652.     gxMapping        vdMapping;
  653.     gxShape            theBitmap;
  654.     gxColorSet        theColorSet;
  655.     
  656.     // First we let others in the chain default the printer object before we do. 
  657.  
  658.     anErr = Forward_GXDefaultPrinter(thePrinter);
  659.     require(anErr == noErr, Forward_GXDefaultPrinter);
  660.     
  661.     // Create the new viewDevice using a fake bitmap 
  662.     {
  663.         gxBitmap    aBitmap;
  664.         
  665.         aBitmap.pixelSize    = 1;
  666.         aBitmap.rowBytes    = 0;
  667.         aBitmap.width        = 0;
  668.         aBitmap.height        = 0;
  669.         aBitmap.image        = (char*)gxMissingImagePointer;
  670.         aBitmap.space        = gxNoSpace;
  671.         aBitmap.set            = nil;
  672.         aBitmap.profile    = nil;
  673.         
  674.         theBitmap = GXNewBitmap(&aBitmap, nil);
  675.         require_action( GXGetGraphicsError(nil) == noErr, NewBitmap, anErr = GXGetGraphicsError(nil); );
  676.         
  677.         vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
  678.         require_action( GXGetGraphicsError(nil) == noErr, NewViewDevice, anErr = GXGetGraphicsError(nil); );
  679.     }
  680.     
  681.     // Now set the view device's color space to be a 1-bit deep indexed space, with two entries (black and white) 
  682.     {
  683.         gxSetColor        theColors[2];
  684.         gxSetColor        *pColor;
  685.         
  686.         pColor = &theColors[0];
  687.         
  688.         // Assign the black and white rgb colors to the indexed color set 
  689.  
  690.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF;            // white 
  691.         pColor++;
  692.         pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000;            // black 
  693.         
  694.         theColorSet = GXNewColorSet(gxRGBSpace, 2, theColors);
  695.         require_action( GXGetGraphicsError(nil) == noErr, NewColorSet, anErr = GXGetGraphicsError(nil); );
  696.  
  697.         SetViewDeviceColorSet(vd, theColorSet);
  698.         require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
  699.     }
  700.     
  701.     // Change the viewDevice mapping to include the scaling factor from 72dpi (screen) to 300 dpi (device). 
  702.     {
  703.         Fixed        xScale;
  704.         Fixed        yScale;
  705.  
  706.         xScale = FixRatio(kHorizHighRes, 72);
  707.         yScale = FixRatio(kVertHighRes, 72);
  708.         
  709.         ResetMapping(&vdMapping);
  710.         ScaleMapping(&vdMapping, xScale, yScale, ff(0), ff(0));
  711.         
  712.         GXSetViewDeviceMapping(vd, &vdMapping);
  713.     }
  714.     
  715.     // Add the newly created viewDevice to the printer object 
  716.  
  717.     anErr = GXAddPrinterViewDevice(thePrinter, vd);
  718.     require_action( GXGetGraphicsError(nil) == noErr, AddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
  719.     
  720.     // Dispose of the temporary shapes we created along the way 
  721.  
  722.     GXDisposeShape(theBitmap);
  723.     GXDisposeColorSet(theColorSet);
  724.     
  725.     return(anErr);
  726.     
  727.     
  728. /******* Clean-up *******/
  729.  
  730. AddPrinterViewDevice:
  731.     GXDisposeViewDevice(vd);
  732.  
  733. SetViewDeviceColorSet:
  734.     GXDisposeColorSet(theColorSet);
  735.     
  736. NewColorSet:
  737. NewViewDevice:
  738.     GXDisposeShape(theBitmap);
  739.  
  740. NewBitmap:
  741. Forward_GXDefaultPrinter:
  742.     return(anErr);
  743. }
  744. /* SD_DefaultPrinter */
  745.  
  746.  
  747. /****************************************************************************************
  748.  
  749.                             SD_SetupPageImageData
  750.                             
  751.     function:
  752.                 This routine is called by the Printing Manager before starting imaging the next
  753.                 page to be imaged.  We intercept this message to adjust the raster imaging
  754.                 system's pageSize rectangle so that it's zero based and long aligned.  We
  755.                 Also compute the LaserWriter SC's device rectangle so we can use it to set
  756.                 the SC's margins in SD_StartSendPage.
  757.                 
  758.     parameters:                
  759.                 theFormat            format of the despooled page
  760.                 hImageData            imaging info for the page
  761.                 
  762.     returns:
  763.                 OSErr
  764.     
  765. ****************************************************************************************/
  766. OSErr SD_SetupPageImageData (gxFormat theFormat, gxShape thePage, gxRasterImageDataHdl    hImageData)
  767. {
  768.     OSErr                     anErr;
  769.     Rect                         deviceRect;
  770.     gxRectangle                pageSize;
  771.     gxRectangle                paperSize;
  772.     gxJob                        theJob = GXGetJob();
  773.     Fixed                        maxPageHeight;
  774.     
  775.     // Let the Printing Manager setup the page successfully before we continue 
  776.  
  777.     anErr = Forward_GXSetupPageImageData(theFormat, thePage, hImageData);
  778.     require(anErr == noErr, Forward_GXSetupPageImageData);
  779.     
  780.     
  781.     // Fetch the paper type for paper that's supposed to be in the printer.  We use its
  782.     // dimensions to restrict the size of the image's page
  783.     // (This is the original format's paper type if unconfigured with a single doc paper type)
  784.     
  785.     GXGetPaperTypeDimensions(GXGetFormatPaperType(theFormat), nil, &paperSize);
  786.  
  787.     // Scale the paperSize to the resolution of the device
  788.     {
  789.         Fixed            xScale;
  790.         Fixed            yScale;
  791.         gxMapping    theMapping;
  792.  
  793.         xScale = FixRatio(kHorizHighRes, 72);
  794.         yScale = FixRatio(kVertHighRes, 72);
  795.         
  796.         ResetMapping(&theMapping);
  797.         ScaleMapping(&theMapping, xScale, yScale, ff(0), ff(0));
  798.         
  799.         MapPoints(&theMapping, 2, (gxPoint *) &paperSize);
  800.     }
  801.     
  802.     // With the paper size scaled to the device resolution, we can now determine the max. page
  803.     // size to allow for this page
  804.     {
  805.         Fixed        paperHeight = paperSize.bottom - paperSize.top;
  806.         
  807.         maxPageHeight = paperHeight;
  808.         if (paperHeight <= kMaxLetterPageHeight)
  809.             maxPageHeight = kMaxLetterPageHeight;
  810.         if (paperHeight >= kMaxLegalPageHeight)
  811.             maxPageHeight = kMaxLegalPageHeight;
  812.     }
  813.     
  814.     // We adjust the pageSize rectangle so it's zero based and long word aligned. 
  815.     // We also align the device rect to be in line with what we expect for the LWSC, 
  816.     // convert it to old QuickDraw coordinates and store it into the globals for 
  817.     // use by SD_StartSendPage. 
  818.     
  819.     pageSize = (*hImageData)->pageSize;
  820.     
  821.     AlignPage(&pageSize, &deviceRect, maxPageHeight);
  822.     
  823.     (*hImageData)->pageSize = pageSize;
  824.     
  825.     anErr = AddCollectionItem(GXGetFormatCollection(theFormat), 'RECT', 0, sizeof(Rect), &deviceRect);
  826.     nrequire(anErr, AddCollectionItemFails);
  827.     
  828.     
  829. /******* Clean-up *******/
  830.  
  831. AddCollectionItemFails:
  832. Forward_GXSetupPageImageData:
  833.     return(anErr);        
  834. }
  835. /* SD_SetupPageImageData */
  836.  
  837.  
  838. /****************************************************************************************
  839.  
  840.                             SD_SetupImageData
  841.                             
  842.     function:
  843.                 This routine is called when the Printing Manager wants us to initialize any
  844.                 imaging data that is specific to our type of printer.  In our case, we use
  845.                 just the default imaging information so all we do is retain the handle for
  846.                 later use.
  847.                 
  848.     parameters:                
  849.                 hImageData        Handle to the raster imaging data
  850.     returns:
  851.                 OSErr
  852.     
  853. ****************************************************************************************/
  854. OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
  855. {
  856.     OSErr                    anErr;
  857.     SpecGlobalsHdl        hGlobals = GetMessageHandlerInstanceContext();
  858.     
  859.     check (hGlobals);
  860.     
  861.     // Retain the raster image data handle for later use 
  862.     (*hGlobals)->hImageData = hImageData;
  863.  
  864.     // Let others in the message chain do their SetupImageData function 
  865.     anErr = Forward_GXSetupImageData(hImageData);
  866.  
  867.     check(anErr == noErr);
  868.     return(anErr);
  869. }
  870. /* SD_SetupImageData */
  871.  
  872.  
  873. /****************************************************************************************
  874.  
  875.                             SD_OpenConnection
  876.                             
  877.     function:
  878.                 This routine is called when the Printing Manager sends the OpenConnection
  879.                 message.  We take this opportunity to locate a LaserWriter SC printer on
  880.                 the SCSI bus, and to make sure it's operational (i.e. no engine or memory
  881.                 failure).
  882.                 
  883.     parameters:        
  884.                 None
  885.                 
  886.     returns:
  887.                 OSErr
  888.     
  889. ****************************************************************************************/
  890. OSErr SD_OpenConnection(void)
  891. {
  892.     OSErr                anErr;
  893.     SCSenseData        senseData;
  894.     gxStatusRecord    *pStatus;
  895.  
  896.     // Make sure that we're running on GX 1.1 or later.
  897.     // We require the gxSetupPageImageData message which was
  898.     // introduced with 1.1.  Normally, GX would check our
  899.     // driver version number and realize that we're too new to
  900.     // run on 1.0.1 or 1.0.2 systems.  Unfortunately, versions
  901.     // of QuickDraw GX prior to 1.1 did not check the minor
  902.     // revision of the version number (meaning driver versions
  903.     // 1.0.0 through 1.9.9 would be abole to run on 1.0.1 and 1.0.2.
  904.     // We can't have that, so we do a check ourselves.
  905.  
  906.     if (!IsGXVersionNewEnough(&anErr))
  907.         return anErr;
  908.  
  909.     // Tell user we're attempting to open a connection to the printer
  910.     anErr = GXReportStatus(kTransmissionStatID, kOpeningConnectionStatIdx);
  911.     require(anErr == noErr, ReportStatus);
  912.             
  913.     // Try to locate the LaserWriter SC on the SCSI bus and make sure it's operational.
  914.     // Keep trying to locate the printer until the user aborts (if it can't be found).
  915.  
  916.     anErr = LaserSC_OpenConnection();
  917.     if (anErr == gxAioCantFindDevice)    //    T => Can't locate device; tell user to turn it on
  918.     {
  919.         // Now we set-up to alert the user that the printer cannot be found
  920.         // Allocate a status record large enough to handle status with the largest buffer size. 
  921.     
  922.         pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
  923.         anErr = MemError();
  924.         require(anErr == noErr, NewPtrClear);
  925.     
  926.         // Initialize the appropriate fields within the status record 
  927.         
  928.         pStatus->statusOwner         = 'drvr';
  929.         pStatus->statResId         = kTransmissionStatID;
  930.         pStatus->statResIndex     = kCantFindPrinterStatIdx;
  931.         pStatus->bufferLen         = gxDefaultStatusBufferSize;
  932.  
  933.         // Now display the alert to the user
  934.         do
  935.         {
  936.             // Issue the alert to the user
  937.             anErr = GXAlertTheUser(pStatus);
  938.             if (anErr == noErr)
  939.             {
  940.                 // Try looking for the device again
  941.                 anErr = LaserSC_OpenConnection();
  942.             }
  943.         }
  944.         while ( (anErr == gxAioCantFindDevice) && (pStatus->dialogResult == 0) );
  945.         
  946.         // If the user dismissed the dialog, we are to abort the job
  947.         if (pStatus->dialogResult != 0)
  948.             anErr = gxPrUserAbortErr;
  949.         
  950.         // Always tell the Printing Finder Extension to dismiss the alert 
  951.         {
  952.             pStatus->statusOwner     = 'univ';
  953.             pStatus->statResId      =    gxUnivAlertStatusResourceId;
  954.             pStatus->statResIndex =    gxUnivPrinterReadyIndex;
  955.             
  956.             // Tell the PFE to remove the alert
  957.             GXAlertTheUser(pStatus);
  958.         }
  959.         
  960.         // Kill the status pointer
  961.         DisposPtr((Ptr) pStatus);
  962.     }
  963.     
  964.     // Forward the message to get standard alerts
  965.     if (anErr == noErr)
  966.         anErr = Forward_GXOpenConnection();
  967.         
  968.     // If any error occurs at this point, then we must abort the open connection
  969.     require(anErr == noErr, LaserSC_OpenConnection);
  970.     
  971.     // In case the printer has just been turned on or reset, issue a request sense 
  972.     // command to clear the unit attention status.
  973.     anErr = LaserSC_GetSenseData(&senseData);
  974.     
  975.     check(anErr == noErr);
  976.     
  977. /******* Clean-up *******/
  978.  
  979. LaserSC_OpenConnection:
  980. NewPtrClear:
  981. ReportStatus:
  982.     return(anErr);
  983. }
  984. /* SD_OpenConnection */
  985.  
  986.  
  987. /****************************************************************************************
  988.  
  989.                             SD_CloseConnection
  990.                             
  991.     function:
  992.                 This routine is called when the Printing Manager issues the CloseConnection
  993.                 message.  We take this opportunity make sure that if we started printing a 
  994.                 page at FinishSendPage time, that we force the page to be printed now, or
  995.                 the job aborted.  We also place the printer into auto-feed mode
  996.                 in case it was in manual feed mode.  This ensures the printer won't complain
  997.                 about there not being any paper in the manual feed slot if we print again soon.  
  998.                 Other than this, there is nothing else we need to do in order to "sever" a 
  999.                 connection to an SC printer.
  1000.                 
  1001.     parameters:    
  1002.                 None
  1003.                 
  1004.     returns:
  1005.                 OSErr
  1006.     
  1007. ****************************************************************************************/
  1008. OSErr SD_CloseConnection (void)
  1009. {
  1010.     OSErr                anErr;
  1011.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1012.     
  1013.     // At this point in time we must make sure that if we previously printed a non-manual feed
  1014.     // page, the page printed successfully.  Here we force the page to be printed successfully,
  1015.     // unless the user aborts the job or we encounter a fatal printer problem. 
  1016.     
  1017.     if ( (*hGlobals)->printedAPage )
  1018.     {
  1019.         gxPaperType    thePaperType;
  1020.  
  1021.         thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
  1022.  
  1023.         // Wait for the page to print
  1024.         
  1025.         anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
  1026.  
  1027.         // Dispose of the cloned format and update the driver's globals
  1028.         
  1029.         (*hGlobals)->printedAPage = false;
  1030.         GXDisposeFormat((*hGlobals)->lastPageFormat);
  1031.  
  1032.         require(anErr == noErr, WaitForPageToPrint);
  1033.     }
  1034.  
  1035.     // Set printer to auto feed and non-buffered mode
  1036.     
  1037.     anErr = LaserSC_SetBuffandFeedMode(false, false);
  1038.     check(anErr == noErr);
  1039.  
  1040.     // Forward the message to get standard alerts, but we don't really care about the result
  1041.     (void) Forward_GXCloseConnection();
  1042.  
  1043.  
  1044. /******* Clean-up *******/
  1045.  
  1046. WaitForPageToPrint:
  1047.     return(anErr);
  1048. }
  1049. /* SD_CloseConnection */
  1050.  
  1051.  
  1052. /****************************************************************************************
  1053.  
  1054.                             SD_StartSendPage
  1055.                             
  1056.     function:
  1057.                 This routine is called by the Printing Manager to signal the start of sending
  1058.                 a new page to the printer.  We first make sure that if we printed a previous
  1059.                 page, the page printed successfully.  Next we query the device to make sure that it's
  1060.                 ready to accept the next page. If there's a problem, we alert the user so he
  1061.                 can resolve it.  Finally, we set the page margins and dimensions in the printer,
  1062.                 and clear out the old frame buffer so there's no left over data.
  1063.                 
  1064.     parameters:                
  1065.                 pageFormat        format for the page to print
  1066.  
  1067.     returns:
  1068.                 OSErr
  1069.     
  1070. ****************************************************************************************/
  1071. OSErr SD_StartSendPage (gxFormat pageFormat)
  1072. {
  1073.     OSErr                anErr;
  1074.     short                leftMargin;                // top left corner of the page
  1075.     short                topMargin;
  1076.     short                bytesPerScanline;        // rowBytes and height of the page
  1077.     short                numScanlines;
  1078.     Rect                actualPage;                // unrotated page    
  1079.     short                deviceStatus;
  1080.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1081.     
  1082.     // Remember the pageFormat so we can access the manual feed setting at FinishSendPage, 
  1083.     // which is the time we actually tell the printer to print the page. 
  1084.  
  1085.     (*hGlobals)->pageFormat = pageFormat;
  1086.  
  1087.     // At this point in time we must make sure that if we previously printed a non-manual feed
  1088.     // page, the page printed successfully.  Here we force the page to be printed successfully,
  1089.     // unless the user aborts the job or we encounter a fatal printer problem. 
  1090.     
  1091.     if ( (*hGlobals)->printedAPage )
  1092.     {
  1093.         gxPaperType    thePaperType;
  1094.  
  1095.         thePaperType = GXGetFormatPaperType((*hGlobals)->lastPageFormat);
  1096.  
  1097.         // Wait for the page to print
  1098.         
  1099.         anErr = WaitForPageToPrint(!isManualFeed, thePaperType);
  1100.  
  1101.         // Dispose of the cloned format and update the driver's globals
  1102.         
  1103.         (*hGlobals)->printedAPage = false;
  1104.         GXDisposeFormat((*hGlobals)->lastPageFormat);
  1105.  
  1106.         require(anErr == noErr, WaitForPageToPrint);
  1107.     }
  1108.  
  1109.     // Check to see if the device is ready to accept the next page of data 
  1110.  
  1111.     anErr = LaserSC_GetDeviceStatus(&deviceStatus);
  1112.     require(anErr == noErr, LaserSC_GetDeviceStatus);
  1113.     
  1114.     // Is the device not ready for more data? 
  1115.     if (deviceStatus != kGoodCondition)
  1116.     {
  1117.         long            printerProblem;
  1118.         short            dialogResult;
  1119.         gxPaperType    thePaperType;
  1120.         gxTrayFeedInfo    trayFeedInfo;
  1121.         long            itemSize = sizeof(trayFeedInfo);
  1122.     
  1123.         // Determine if this is a manual feed job 
  1124.  
  1125.         thePaperType = GXGetFormatPaperType(pageFormat);
  1126.  
  1127.         anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1128.         nrequire(anErr, GetCollectionItem);
  1129.  
  1130.         // Query the printer to determine its state 
  1131.  
  1132.         anErr = FindPrinterProblem(&printerProblem, nil);
  1133.         require(anErr == noErr, FindPrinterProblem);
  1134.         
  1135.         // If the printer is out of paper and we're doing a manual feed job, then don't 
  1136.         // alert the user now.  Wait until we actually try to print a page (it gives him more 
  1137.         // time to put the paper in - refer to SD_FinishSendPage). 
  1138.  
  1139.         if ( (GetStatResIndex(printerProblem) != kOutOfPaperStatIdx) || !trayFeedInfo.manualFeedThisPage )
  1140.         {
  1141.             // Based upon the state of the printer, inform/alert the user to the problem 
  1142.             // so he can correct it. 
  1143.  
  1144.             anErr = ResolvePrinterProblem(printerProblem, !isManualFeed, thePaperType, &dialogResult);
  1145.             require(anErr == noErr, ResolvePrinterProblem);
  1146.         }
  1147.     }
  1148.  
  1149.     // If we get here, the printer must be ready for data.  Tell user we're preparing the data. 
  1150.  
  1151.     anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
  1152.     require(anErr == noErr, ReportStatus);
  1153.         
  1154.     // Now we need to set the printer's page margins, as well as the page dimensions. 
  1155.     // We compute the needed values from the deviceRect we initialized at despool page 
  1156.     // time. Recall that the deviceRect represents the imaging rectangle within the 
  1157.     // printers RAM. 
  1158.     
  1159.     GetCollectionItem(GXGetFormatCollection(pageFormat), 'RECT', 0, nil, &actualPage);
  1160.     leftMargin             =     actualPage.left >> 3;                                // left margin is specified in number of bytes 
  1161.     topMargin             =     actualPage.top;                                        // top margin is specified in number of scan lines 
  1162.     bytesPerScanline     =     (actualPage.right - actualPage.left) >> 3;    // bytesPerScanline is the number of bytes in a single scan line 
  1163.     numScanlines         =     actualPage.bottom - actualPage.top;                // numScanlines is just the line height of the device rectangle 
  1164.     
  1165.     // Force the margins to be at least as large as the minimum supported by the SC printer 
  1166.  
  1167.     if (topMargin < kMinSCTopMargin)
  1168.         topMargin = kMinSCTopMargin;
  1169.  
  1170.     if (leftMargin < kMinSCLeftMargin)
  1171.         leftMargin = kMinSCLeftMargin;
  1172.         
  1173.     // Set the top and left margin for the printer 
  1174.  
  1175.     anErr = LaserSC_SetPageMargins(leftMargin, topMargin);
  1176.     require(anErr == noErr, LaserSC_SetPageMargins);
  1177.     
  1178.     // Set the page dimensions for the printer 
  1179.  
  1180.     anErr = LaserSC_SetPageDimensions(bytesPerScanline, numScanlines);
  1181.     require(anErr == noErr, LaserSC_SetPageDimensions);
  1182.             
  1183.     // Make sure the printers page frame buffer is cleared out.  We offset the 
  1184.     // actualPage rectangle because the printer assumes the top left corner of the 
  1185.     // imaging area rectangle is (0, 0). 
  1186.     
  1187.     OffsetRect(&actualPage, -actualPage.left, -actualPage.top);
  1188.     anErr = LaserSC_ClearBits(&actualPage);
  1189.  
  1190.     check(anErr == noErr);
  1191.     
  1192.     
  1193. /******* Cleanup *******/
  1194.  
  1195. LaserSC_SetPageDimensions:
  1196. LaserSC_SetPageMargins:
  1197. ReportStatus:
  1198. ResolvePrinterProblem:
  1199. FindPrinterProblem:
  1200. GetCollectionItem:
  1201. LaserSC_GetDeviceStatus:
  1202. WaitForPageToPrint:
  1203.     return(anErr);
  1204. }
  1205. /* SD_StartSendPage */
  1206.  
  1207.  
  1208. /****************************************************************************************
  1209.  
  1210.                             SD_FinishSendPage
  1211.                             
  1212.     function:
  1213.                 This routine is called by the Printing Manager to signal that we're at the
  1214.                 end of the current page.  If we're not processing a manual feed job, then we
  1215.                 simply print the page that's in the printers RAM and alert the user to any
  1216.                 errors that result.  If it's a manual feed job, then we first prompt the user
  1217.                 to put paper in the printer if there isn't any paper in there currently.  For
  1218.                 auto-feed jobs, we start printing now, but don't wait for it to complete
  1219.                 until the next StartSendPage or CloseConnection message is issued.
  1220.                 
  1221.     parameters:    
  1222.                 None
  1223.                 
  1224.     returns:
  1225.                 OSErr
  1226.     
  1227. ****************************************************************************************/
  1228. OSErr SD_FinishSendPage (void)
  1229. {
  1230.     OSErr                anErr;
  1231.     gxPaperType        thePaperType;
  1232.     gxTrayFeedInfo    trayFeedInfo;
  1233.     long                itemSize = sizeof(trayFeedInfo);
  1234.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1235.     
  1236.     // Determine if this is a manual feed job 
  1237.  
  1238.     thePaperType = GXGetFormatPaperType((*hGlobals)->pageFormat);
  1239.     
  1240.     anErr = GetCollectionItem(GXGetJobCollection( GXGetJob() ), gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
  1241.     nrequire(anErr, GetCollectionItem);
  1242.     
  1243.     // Set the manual feed mode of the printer based upon the paper configuration, and set the 
  1244.     // printer's buffered mode so that the SC Print and Clear Bits commands return immediately 
  1245.     // without waiting for the commands to complete. 
  1246.     
  1247.     anErr = LaserSC_SetBuffandFeedMode(trayFeedInfo.manualFeedThisPage, true);
  1248.     require(anErr == noErr, LaserSC_SetBuffandFeedMode);
  1249.  
  1250.     // Indicate that we are now printing a page
  1251.     
  1252.     anErr = GXReportStatus(kTransmissionStatID, kPrintingPageStatIdx);
  1253.     require(anErr == noErr, ReportStatus);
  1254.  
  1255.     // Now we issue the Print command to start printing the buffered page.  If we're not printing a
  1256.     // manual feed job, then we just continue on and will check to make sure the page
  1257.     // completed printing at the next StartSendPage message or the next CloseConnection message.
  1258.     // If we're printing a manual feed job and there isn't any paper in the printer, then the printer 
  1259.     // will return an "end-of-media" error and we will alert the user to put paper in 
  1260.     // the printer. We continue looping, re-issuing the Print command as needed until 
  1261.     // the page is either printed, or the user aborts the job. 
  1262.     
  1263.     // Issue the print command to start the page printing 
  1264.  
  1265.     anErr = LaserSC_PrintPage(    false,             // T => print at 8 page per minute rate; F => print normal rate
  1266.                                         false);             // T => clear printer's page buffer while printing; F => don't clear buffer
  1267.     require(anErr == noErr, LaserSC_PrintPage);
  1268.  
  1269.     // If this is a manual feed job, wait for the page to print since we need to tell the user to put paper in the printer.
  1270.     if (trayFeedInfo.manualFeedThisPage)
  1271.     {
  1272.         anErr = WaitForPageToPrint(trayFeedInfo.manualFeedThisPage, thePaperType);
  1273.         check(anErr == noErr);
  1274.  
  1275.         (*hGlobals)->printedAPage = false;    //    No need to check on the printed page later
  1276.     }
  1277.     else    //    T => Remember that we've started printing a page so we can check on it later
  1278.     {
  1279.         gxFormat    theFormat;
  1280.         
  1281.         (*hGlobals)->printedAPage = true;
  1282.         
  1283.         // Clone the format so we can reference it again at the next StartSendPage or CloseConnection time.  The
  1284.         // driver disposes of the clone at that time.
  1285.         
  1286.         theFormat = GXCloneFormat((*hGlobals)->pageFormat);
  1287.         (*hGlobals)->lastPageFormat = theFormat;
  1288.     }
  1289.     
  1290.     
  1291. /******* Cleanup *******/
  1292.  
  1293. LaserSC_PrintPage:
  1294. ReportStatus:
  1295. LaserSC_SetBuffandFeedMode:
  1296. GetCollectionItem:
  1297.     return(anErr);
  1298. }
  1299. /* SD_FinishSendPage */
  1300.  
  1301.  
  1302. /****************************************************************************************
  1303.  
  1304.                             SD_WriteData
  1305.                             
  1306.     function:
  1307.                 This routine is called by the Printing Manager to send data to the device.
  1308.                 This driver uses the routine to complete, or save in globals temporarily, 
  1309.                 the next SCSI command to be issued to the device.  It determines whether to
  1310.                 do the command now or save it for later (to be done in SD_CheckStatus or 
  1311.                 SD_GetDeviceStatus) by examining which SCSI command is to be executed.
  1312.                 
  1313.                 If the pData parameter is non-nil, then the routine assumes pData references
  1314.                 a SCSI command to be issued to the device, and the length parameter specifies
  1315.                 the size of the command.  If the SCSI command does not require additional
  1316.                 data to be sent/received from the device, then this routine calls the SCSI Manager
  1317.                 routines SCSIGet, SCSISelect, and SCSICmd in order to complete the SCSI command
  1318.                 during this call.  If the SCSI command requires an additional data transfer, 
  1319.                 then the SCSI command is saved in the driver's globals, and will be issued
  1320.                 on a subsequent call to SD_CheckStatus or SD_GetDeviceStatus (when the other
  1321.                 portion of the data transfer is performed) and the command can be completed.
  1322.                 
  1323.     parameters:        
  1324.                 pData            pointer to SCSI command to perform
  1325.                 length        size of the SCSI command (bytes)
  1326.                 
  1327.     returns:
  1328.                 OSErr
  1329.  
  1330. ****************************************************************************************/
  1331. OSErr SD_WriteData(Ptr pData, long length)
  1332. {
  1333.     OSErr                anErr = noErr;
  1334.     SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
  1335.     
  1336.     // Are we to issue a new SCSI command to the device?
  1337.     if (pData != nil)
  1338.     {
  1339.         short        scsiStatus;
  1340.         short        message;
  1341.  
  1342.         // Remember what timeout value to use for this printer command when we complete the op.
  1343.         (*hGlobals)->timeoutForSCSIComplete = LaserSC_GetTimeoutForSCSICmnd(*((short *) pData));
  1344.         
  1345.         // If this SCSI command is one we can complete now (i.e. no other data transfer is
  1346.         // required), then we do it now. Otherwise, we save the command in the driver's
  1347.         // globals and it will be executed on a subsequent call to SD_CheckStatus or
  1348.         // SD_GetDeviceStatus.
  1349.         
  1350.         switch ( *((short *) pData) )
  1351.         {
  1352.              case kSCPrinterReady:        //    These SC commands consist only of SCSI commands; do them now
  1353.             case kSCResetPrinter:
  1354.             case kSCPrint:
  1355.             
  1356.                 // Get control of the SCSI bus before issuing the command
  1357.                 anErr = SCSIGet();
  1358.                 require(anErr == noErr, SCSIGetFails);
  1359.                 
  1360.                 // Select the target device on the SCSI bus
  1361.                 anErr = SCSISelect((*hGlobals)->deviceNum);
  1362.                 require(anErr == noErr, SCSISelectFails);
  1363.                     
  1364.                 // Now send the command to the device
  1365.                 SCSICmd(pData, length);
  1366.  
  1367.                 // Now force completion of the SCSI command
  1368.                 anErr = SCSIComplete(&scsiStatus, &message, (*hGlobals)->timeoutForSCSIComplete);
  1369.                 require(anErr == noErr, SCSICompleteFails);
  1370.  
  1371.                 // Remember the last SCSI status in the globals
  1372.                 (*hGlobals)->lastSCSIStatus = scsiStatus;
  1373.                 
  1374.                 break;
  1375.             
  1376.             default:                            //    All other SC commands require some data transfer with the SCSI command
  1377.                 
  1378.                 // Save the SCSI command in the driver's globals for later use
  1379.                 BlockMove(pData, (Ptr) (*hGlobals)->scsiCommand, length);
  1380.                 
  1381.                 // If we're starting a DrawBits command, make sure the appropriate globals are initialized
  1382.                 if ( *((short *) pData) == kSCDrawBits )
  1383.                     (*hGlobals)->haveDrawBitsParams = false;
  1384.         }
  1385.         
  1386.     }
  1387.     
  1388.  
  1389. /******* Clean-up *******/
  1390.  
  1391. SCSISelectFails:
  1392. SCSIGetFails:
  1393. SCSICompleteFails:
  1394.     return(anErr);
  1395. }
  1396. /* SD_WriteData */
  1397.  
  1398.  
  1399. /****************************************************************************************
  1400.  
  1401.                             SD_CheckStatus
  1402.                             
  1403.     function:
  1404.                 This routine is called by the Printing Manager to mark places in which to check
  1405.                 the status of the device.  This driver does not use this routine to retrieve 
  1406.                 the status of the device. Rather, it uses the routine to send data to the 
  1407.                 device.
  1408.                 
  1409.                 The pData parameter points to the data to be sent, and the length parameter
  1410.                 specifies how many bytes to transfer.  The statusType parameter specifies
  1411.                 the number of bytes to transfer in each SCSI data burst, and whether we should
  1412.                 use the SCSIWrite or SCSIWBlind routines to accomplish the data transfer.  If
  1413.                 statusType is positive, then we should use SCSIWrite; otherwise we use should
  1414.                 SCSIWBlind.  The absolute value of statusType specifies the number of bytes to
  1415.                 transfer in each SCSI data burst.
  1416.                 
  1417.                 When this routine is called for any SCSI command other than DrawBits, the command
  1418.                 is completed during this call.  If the call is for the SC DrawBits command, then
  1419.                 we only complete the command if the routine is being called to with the bitmap
  1420.                 data to be sent to the device (when the global variable haveDrawBitsParams is
  1421.                 true).
  1422.                 
  1423.     parameters:    
  1424.                 pData            pointer to data to send to device
  1425.                 length        number of bytes to send to the device
  1426.                 statusType    < 0 => do transfer using SCSIWBlind
  1427.                                 >= 0 => do transfer using SCSIWrite
  1428.                                 abs(statusType) is number of bytes to transfer in each SCSI data burst
  1429.                 owner            indicates who generated the CheckStatus request
  1430.                 
  1431.     returns:
  1432.                 OSErr
  1433.  
  1434. ****************************************************************************************/
  1435. OSErr SD_CheckStatus(Ptr pData, long length, short statusType, OSType owner)
  1436. {
  1437.     OSErr                    anErr = noErr;
  1438.     SCSIInstr            tibProgram[9];
  1439.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1440.     SpecGlobalsPtr        pGlobals;
  1441.     Boolean                doCmndNow = true;
  1442.     
  1443.     HLock((Handle) hGlobals);
  1444.     pGlobals = *hGlobals;
  1445.         
  1446.     // Is this a CheckStatus request that we generated?
  1447.     if (owner == kDrvrCreatorType)
  1448.     {
  1449.         // Check to see if it's a DrawBits command and that we now have the bitmap data
  1450.         if ( pGlobals->scsiCommand[0] == kSCDrawBits )
  1451.         {
  1452.             // Have we already received the parameters to the DrawBits command?
  1453.             if ( pGlobals->haveDrawBitsParams )
  1454.             {
  1455.                 // Get control of the SCSI bus before issuing the command
  1456.                 anErr = SCSIGet();
  1457.                 require(anErr == noErr, SCSIGetFails1);
  1458.                 
  1459.                 // Select the target device on the SCSI bus
  1460.                 anErr = SCSISelect(pGlobals->deviceNum);
  1461.                 require(anErr == noErr, SCSISelectFails1);
  1462.                     
  1463.                 // Now send the command to the device
  1464.                 SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1465.                 
  1466.                 // Now we generate a SCSI Manager TIB program to send the parameters to the DrawBits command
  1467.                 GenTIBProgram(tibProgram, (Ptr) pGlobals->drawbitsParams, 10, 10);
  1468.                 
  1469.                 // Send the DrawBits parameters to the device
  1470.                 anErr = SCSIWrite((Ptr) tibProgram);
  1471.                 require(anErr == noErr, SCSIWriteFails1);
  1472.             }
  1473.             else    //    T => Client is calling us with the DrawBits parameters; save them for later use
  1474.             {
  1475.                 BlockMove(pData, (Ptr) pGlobals->drawbitsParams, length);
  1476.                 pGlobals->haveDrawBitsParams = true;
  1477.                 doCmndNow = false;
  1478.             }
  1479.         }
  1480.         else    //    T => not a DrawBits command. Complete the command during this call
  1481.         {
  1482.             // Get control of the SCSI bus before issuing the command
  1483.             anErr = SCSIGet();
  1484.             require(anErr == noErr, SCSIGetFails2);
  1485.             
  1486.             // Select the target device on the SCSI bus
  1487.             anErr = SCSISelect(pGlobals->deviceNum);
  1488.             require(anErr == noErr, SCSISelectFails2);
  1489.                 
  1490.             // Now send the command to the device
  1491.             SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1492.         }
  1493.         
  1494.         // Are we completing the command during this call?
  1495.         if (doCmndNow)
  1496.         {
  1497.             short        scsiStatus;
  1498.             short        message;
  1499.  
  1500.             // Create a SCSI Manager TIB program to perform the last piece of the SCSI data transfer
  1501.             GenTIBProgram(tibProgram, pData, length, abs(statusType));
  1502.             
  1503.             // Determine which SCSI Manager command to perform and send the data
  1504.             if (statusType >= 0)
  1505.             {
  1506.                 anErr = SCSIWrite((Ptr) tibProgram);
  1507.                 require(anErr == noErr, SCSIWriteFails2);
  1508.             }
  1509.             else    //    T => Do data transfer using a blind transfer
  1510.             {
  1511.                 anErr = SCSIWBlind((Ptr) tibProgram);
  1512.                 require(anErr == noErr, SCSIWBlindFails);
  1513.             }
  1514.             
  1515.             // Now force completion of the SCSI command
  1516.             anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
  1517.             require(anErr == noErr, SCSICompleteFails);
  1518.  
  1519.             // Remember the last SCSI status in the globals
  1520.             pGlobals->lastSCSIStatus = scsiStatus;
  1521.         }
  1522.         // else - We received the DrawBits parameters; can't do command now
  1523.     }
  1524.     else    //    T => This is not our CheckStatus request; pass it along the message chain
  1525.     {
  1526.         anErr = Forward_GXCheckStatus(pData, length, statusType, owner);
  1527.         require(anErr == noErr, Forward_GXCheckStatusFails);
  1528.     }
  1529.  
  1530. /******* Clean-up *******/
  1531.  
  1532. SCSICompleteFails:
  1533. SCSIWBlindFails:
  1534. SCSIWriteFails2:
  1535. SCSIWriteFails1:
  1536. SCSISelectFails2:
  1537. SCSIGetFails2:
  1538. SCSISelectFails1:
  1539. SCSIGetFails1:
  1540. Forward_GXCheckStatusFails:
  1541.     HUnlock((Handle) hGlobals);
  1542.  
  1543.     return(anErr);
  1544. }
  1545. /* SD_CheckStatus */
  1546.  
  1547.  
  1548. /****************************************************************************************
  1549.  
  1550.                             SD_GetDeviceStatus
  1551.                             
  1552.     function:
  1553.                 This routine is called by the Printing Manager to query the current status
  1554.                 of the device.  This driver does not use this routine to retrieve 
  1555.                 the status of the device. Rather, it uses the routine to retrieve the
  1556.                 status value returned from last SCSI Manager SCSIComplete command and to
  1557.                 retrieve data from the device.
  1558.                 
  1559.                 If the responseData pointer is non-nil, then the routine will attempt to
  1560.                 read data from the printer.  In this case, responseData points to the buffer
  1561.                 to hold the data received; responseSize specifies the number of bytes to
  1562.                 read; and cmdSize specifies the number of bytes to transfer in each SCSI data 
  1563.                 burst, and whether we should use the SCSIRead or SCSIRBlind routines to 
  1564.                 accomplish the data transfer.  If cmdSize is positive, then we should use 
  1565.                 SCSIRead; otherwise we use should SCSIRBlind.  The absolute value of 
  1566.                 cmdSize specifies the number of bytes to transfer in each SCSI data burst.
  1567.                 
  1568.                 If the responseData pointer is nil, then the routine returns the status 
  1569.                 value from the last SCSI Manager SCSIComplete command.  All other
  1570.                 parameters are ignored.
  1571.                 
  1572.     parameters:    
  1573.                 cmdData            not used
  1574.                 cmdSize            if responseData != nil then
  1575.                                     < 0 => do transfer using SCSIRBlind
  1576.                                     >= 0 => do transfer using SCSIRead
  1577.                                     abs(cmdSize) is number of bytes to transfer in each SCSI data burst
  1578.                 responseData    if responseData != nil, read data from device; otherwise ignored
  1579.                 responseSize    if responseData != nil, specifies the number of bytes to read from device;
  1580.                                     Otherwise, returns the status from the last SCSIComplete call
  1581.                 termination        not used
  1582.                 
  1583.     returns:
  1584.                 OSErr
  1585.  
  1586. ****************************************************************************************/
  1587. OSErr SD_GetDeviceStatus(Ptr cmdData, long cmdSize, Ptr responseData, long *responseSize, Str255 termination)
  1588. {
  1589.     #pragma unused (cmdData, termination)
  1590.     
  1591.     OSErr                    anErr = noErr;
  1592.     SpecGlobalsHdl     hGlobals = GetMessageHandlerInstanceContext();
  1593.     SCSIInstr            tibProgram[9];
  1594.     SpecGlobalsPtr        pGlobals;
  1595.     
  1596.     HLock((Handle) hGlobals);
  1597.     pGlobals = *hGlobals;
  1598.         
  1599.     // Are we to read some data from the device?
  1600.     if (responseData != nil)
  1601.     {
  1602.         short        scsiStatus;
  1603.         short        message;
  1604.  
  1605.         // Get control of the SCSI bus before issuing the command
  1606.         anErr = SCSIGet();
  1607.         require(anErr == noErr, SCSIGetFails);
  1608.         
  1609.         // Select the target device on the SCSI bus
  1610.         anErr = SCSISelect(pGlobals->deviceNum);
  1611.         require(anErr == noErr, SCSISelectFails);
  1612.             
  1613.         // Now send the command to the device
  1614.         SCSICmd((Ptr) pGlobals->scsiCommand, 6);
  1615.  
  1616.         // Create a SCSI Manager TIB program to perform the SCSI data transfer
  1617.         GenTIBProgram(tibProgram, responseData, *responseSize, abs(cmdSize));
  1618.         
  1619.         // Determine which SCSI Manager command to perform and read the data
  1620.         if (cmdSize >= 0)
  1621.         {
  1622.             anErr = SCSIRead((Ptr) tibProgram);
  1623.             require(anErr == noErr, SCSIReadFails);
  1624.         }
  1625.         else    //    T => Do data transfer using a blind transfer
  1626.         {
  1627.             anErr = SCSIRBlind((Ptr) tibProgram);
  1628.             require(anErr == noErr, SCSIRBlindFails);
  1629.         }
  1630.             
  1631.         // Now force completion of the SCSI command
  1632.         anErr = SCSIComplete(&scsiStatus, &message, pGlobals->timeoutForSCSIComplete);
  1633.         require(anErr == noErr, SCSICompleteFails);
  1634.  
  1635.         // Remember the last SCSI status in the globals
  1636.         pGlobals->lastSCSIStatus = scsiStatus;
  1637.     }
  1638.     else    // T => Return the last SCSI status in the responseSize parameter
  1639.         *responseSize = (*hGlobals)->lastSCSIStatus;
  1640.     
  1641.  
  1642. /******* Clean-up *******/
  1643.  
  1644. SCSICompleteFails:
  1645. SCSIRBlindFails:
  1646. SCSIReadFails:
  1647. SCSISelectFails:
  1648. SCSIGetFails:
  1649.     HUnlock((Handle) hGlobals);
  1650.  
  1651.     return(anErr);    
  1652. }
  1653. /* SD_GetDeviceStatus */
  1654.  
  1655.  
  1656. /****************************************************************************************
  1657.  
  1658.                             SD_CreateImageFile
  1659.                             
  1660.     function:
  1661.                 This routine is called by the Printing Manager when a new image file is to
  1662.                 be created.  This driver overrides this message for debugging purposes only.
  1663.                 If the SCImageFileDebugFlag is defined, we forward the message with a 
  1664.                 new set of imageFileOptions, namely "makeImageFile + entireFile".  This forces the
  1665.                 Universal Driver to image the image file.  This allows us to test the proper
  1666.                 generation of image files.  If the compile time flag is not set, then the 
  1667.                 this routine is a no-op; it simply forwards the message on to others in the
  1668.                 message chain.
  1669.                 
  1670.     parameters:    
  1671.                 fileSpec                file spec for the image file
  1672.                 imageFileOptions    options to apply to the creation of the image file
  1673.                 theImageFile        a Printing Manager reference to the image file
  1674.                 
  1675.     returns:
  1676.                 OSErr
  1677.  
  1678. ****************************************************************************************/
  1679. OSErr SD_CreateImageFile(FSSpecPtr fileSpec, long imageFileOptions, long *theImageFile)
  1680. {
  1681.     OSErr        anErr = noErr;
  1682.     
  1683.     #ifdef SCImageFileDebugFlag
  1684.         anErr = Forward_GXCreateImageFile(fileSpec, makeImageFile + entireFile, theImageFile);
  1685.     #else
  1686.         anErr = Forward_GXCreateImageFile(fileSpec, imageFileOptions, theImageFile);
  1687.     #endif
  1688.     
  1689.     check(anErr == noErr);
  1690.     return(anErr);
  1691. }
  1692. /* SD_CreateImageFile */
  1693.  
  1694.  
  1695. /****************************************************************************************
  1696.  
  1697.                             SD_FetchTaggedData
  1698.                             
  1699.     function:
  1700.                 This routine is called by the Printing Manager when a a resource is fetched
  1701.                 from some resource file.  This driver overrides this message to determine
  1702.                 when someone is fetching the rasterPrefsType resource.  If this resource
  1703.                 is being fetched, and the job we're processing is not best quality, then
  1704.                 we disable the halftoning feature in the resource.  This should make the
  1705.                 printing of just graphics a little bit faster.
  1706.                 
  1707.     parameters:    
  1708.                 rsrcType            type of the resource being retrieved
  1709.                 rsrcID            resource ID of the resource being retrieved
  1710.                 theRsrc            handle to the resource retrieved
  1711.                 owner                indicates who is issuing the request; only look at owners == 'drvr'
  1712.                 
  1713.     returns:
  1714.                 OSErr
  1715.  
  1716. ****************************************************************************************/
  1717. OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
  1718. {
  1719.     OSErr        anErr;
  1720.     
  1721.     // First fetch the actual resource
  1722.     anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
  1723.     require(anErr == noErr, FetchTaggedData);
  1724.     
  1725.     if (    (owner == 'drvr')                        &&        //    T => Fetching a driver resource
  1726.             (rsrcType == gxRasterPrefsType)    &&        //    T => type is 'rdip'
  1727.             (rsrcID == gxRasterPrefsID)        &&        //    T => ID is 0
  1728.             ( !JobIsBestQuality() )                        //    T => Doing rough output
  1729.         )
  1730.     {
  1731.         ( (gxRasterPrefsPtr) **theRsrc)->planeSetup[0].planeOptions = gxDontSetHalftone;
  1732.     }
  1733.  
  1734.  
  1735. /******* Clean-up *******/
  1736.  
  1737. FetchTaggedData:
  1738.     return(anErr);
  1739. }
  1740. /* SD_FetchTaggedData */
  1741.  
  1742.  
  1743. /****************************************************************************************
  1744.  
  1745.                             SD_RasterDataIn
  1746.                             
  1747.     function:
  1748.                 This routine is called by the Printing Manager when it has completed rendering
  1749.                 a single portion of a raster page.  It calls this routine to send the bitmap
  1750.                 to the device.  The data for the SC does not require any special packaging
  1751.                 other than that the rectangle to draw in must be converted to a QuickDraw
  1752.                 rectangle and it's left edge must be zero based (this is what the SC engine
  1753.                 expects, otherwise it returns an error 5).  We update the status display
  1754.                 and send the data to the device.
  1755.                 
  1756.     parameters:        
  1757.                 hOffscreen            handle to the structure which references the offscreen bitmap of data
  1758.                 bandRect                rectangle in which to place the data on the page
  1759.                 dirtyRects            dirty area within that rectangle
  1760.                 
  1761.     returns:
  1762.                 OSErr
  1763.  
  1764. ****************************************************************************************/
  1765. OSErr SD_RasterDataIn (gxOffscreenHdl hOffscreen, gxRectangle *bandRect, gxRectangle *dirtyRect)
  1766. {
  1767.  
  1768.     OSErr            anErr;
  1769.     Rect            rDirty;
  1770.     char            lockState;
  1771.  
  1772. /*
  1773. // Handy dandy banding debugging code    
  1774.     dprintf(notrace, "bandTop %d bandLeft %d bandBottom %d bandRight %d\n", 
  1775.                         bandRect->top >> 16,
  1776.                         bandRect->left >> 16,
  1777.                         bandRect->bottom >> 16,
  1778.                         bandRect->right >> 16);
  1779.     dprintf(notrace, "dirtyTop %d dirtyLeft %d dirtyBottom %d dirtyRight %d\n", 
  1780.                         dirtyRect->top >> 16,
  1781.                         dirtyRect->left >> 16,
  1782.                         dirtyRect->bottom >> 16,
  1783.                         dirtyRect->right >> 16);
  1784. */
  1785.  
  1786.     // Create the boundary rectangle in which to "draw" the bitmap on the printer 
  1787.  
  1788.     SetRect(&rDirty,     F2S(bandRect->left),
  1789.                             F2S(dirtyRect->top),
  1790.                             F2S(bandRect->right),
  1791.                             F2S(dirtyRect->bottom) );
  1792.     
  1793.     // Make sure this rectangle's left edge is zero based (required by SC) 
  1794.  
  1795.     rDirty.right -= rDirty.left;
  1796.     rDirty.left = 0;
  1797.     
  1798.     // Give the app. a chance to run 
  1799.  
  1800.     anErr = GXJobIdle();
  1801.     require(anErr == noErr, JobIdle);
  1802.     
  1803.     // Update the status display to indicate that we're sending data to the printer         
  1804.  
  1805.     anErr = GXReportStatus(kTransmissionStatID, kSendingPartOfPageStatIdx);
  1806.     require(anErr == noErr, ReportStatus);
  1807.     
  1808.     // Make sure the offscreen bitmap is locked down before we draw 
  1809.  
  1810.     lockState = HGetState((Handle) hOffscreen);
  1811.     HLock((Handle) hOffscreen);
  1812.     {
  1813.         gxBitmap        *pBitmap;
  1814.         Ptr            image;
  1815.         
  1816.         pBitmap = &(*hOffscreen)->thePlanes[0].theBits;
  1817.         image = pBitmap->image;
  1818.         image += pBitmap->rowBytes * (rDirty.top - F2S(bandRect->top));
  1819.         anErr = LaserSC_DrawBits(image, &rDirty, pBitmap->rowBytes, srcCopy);
  1820.     }
  1821.     HSetState((Handle) hOffscreen, lockState);
  1822.  
  1823.     require(anErr == noErr, LaserSC_DrawBits);
  1824.     
  1825.     // Update the status display to indicate that we're preparing the next chunk of data         
  1826.  
  1827.     anErr = GXReportStatus(kTransmissionStatID, kPreparingPartOfPageStatIdx);
  1828.     require(anErr == noErr, ReportStatus2);
  1829.         
  1830.     
  1831. /******* Cleanup *******/
  1832.  
  1833. ReportStatus2:
  1834. LaserSC_DrawBits:
  1835. ReportStatus:
  1836. JobIdle:
  1837.     return(anErr);
  1838. }
  1839. /* SD_RasterDataIn */
  1840.  
  1841. /****************************************************************************************
  1842.  
  1843.                             SD_DoesPaperFit
  1844.                             
  1845.     function:
  1846.                 This routine is called by the Printing Manager when the user selects the input
  1847.                 trays dialog from the printing menu.  The driver checks the page dimensions to
  1848.                 see if it is physically possible to store the paper in the printer.
  1849.                 
  1850.     parameters:        
  1851.                 paper            papertype to check
  1852.                 fits            (returned)  true if dimensions fit, false otherwise
  1853.                 
  1854.     returns:
  1855.                 noErr
  1856.  
  1857. ****************************************************************************************/
  1858. OSErr SD_DoesPaperFit (gxTrayIndex tray, gxPaperType paper, Boolean *fits)
  1859. {
  1860.     gxRectangle    paperSize;
  1861.     Fixed            paperWidth, paperHeight, tempFixed;
  1862.  
  1863.      GXGetPaperTypeDimensions(paper, nil, &paperSize);    
  1864.     paperWidth     =    paperSize.right - paperSize.left;
  1865.     paperHeight =    paperSize.bottom - paperSize.top;
  1866.     
  1867.     *fits = false;
  1868.     
  1869. // for simplicity, make sure paperHeight >= paperWidth
  1870.     
  1871.     if ( paperWidth > paperHeight ) {
  1872.         tempFixed = paperWidth;
  1873.         paperWidth = paperHeight;
  1874.         paperHeight = tempFixed;
  1875.         }
  1876.  
  1877. // the SC supports 5 paper sizes
  1878. // widths range from kEnvelopeWidth to kUSLetterWidth
  1879. // heights range from kEnvelopeHeight to kUSLegalHeight
  1880.  
  1881.     if (( paperWidth >= kEnvelopeWidth )  && ( paperWidth <= kUSLetterWidth ))
  1882.         if (( paperHeight >= kEnvelopeHeight ) && (paperHeight <= kUSLegalHeight )) {
  1883.         
  1884.             if ( paperWidth == kUSLetterWidth ) {
  1885.                 if (( paperHeight == kUSLetterHeight ) || ( paperHeight == kUSLegalHeight ))
  1886.                     *fits = true;
  1887.                 }
  1888.             else if (( paperWidth == kA4LetterWidth ) && ( paperHeight == kA4LetterHeight ))
  1889.                 *fits = true;
  1890.             else if (( paperWidth == kB5LetterWidth ) && ( paperHeight == kB5LetterHeight ))
  1891.                 *fits = true;
  1892.             else if (( paperWidth == kEnvelopeWidth ) && ( paperHeight == kEnvelopeHeight ))
  1893.                 *fits = true;
  1894.             }
  1895.     
  1896.     return( noErr );
  1897. }
  1898.